# 深拷贝
import copy

from py2neo import Graph, Node, NodeMatcher, Relationship, Subgraph

# 数据库操作方法
# 上一级再上一级
from db.databaseOperation import (
    connect,
    addNodeByTx,
    addNodes,
    deleteAllNodes
)
# 工具方法
from utils.printMessage import (
    logMessage
)
from .getData import (
    # 常量
    REGION_NODE_RELATIONSHIP_KEY,
    REGION_NODE_USEFUL_KEY,
    # 方法
    getRegionData,
    getMagicalAttitudeData,
    getManageSystemData,
    getEnvironmentData,
    getTechnologicalLevelData
)
from ..common import (
    getNodeTypeData,
    getRelationshipTypeData
)

def parseDataAndCreateRegionNode(graph, nodeTypeData, data):
    regionNodeType = nodeTypeData['type']
    regionNodeName = nodeTypeData['desc']
    regionNodeDataList = copy.deepcopy(data)

    # 最终有效的数据,通过有效的且需要的数据进行数据过滤
    finalValidDataList = []
    for item in regionNodeDataList:
        tempObj = {}
        for key in REGION_NODE_USEFUL_KEY:
            if key in item:
                # 特殊逻辑,将里面的url取出来，label为无用数据
                if key == 'link':
                    if 'url' in item['link']:
                        tempObj['link'] = item['link']['url'].replace('{LOCALE}','zh_CN')
                elif key == 'title':
                    tempObj['name'] = item['title']
                else:
                    tempObj[key] = item[key]
        finalValidDataList.append(tempObj)

    # 创建区域数据结点
    addNodes(graph, regionNodeType, finalValidDataList, regionNodeName)

# 通过desc寻找结点类型
def findRelationshipTypeFromName(name, relationshipTypeObj):
    for key in relationshipTypeObj:
        item = relationshipTypeObj[key]
        if item['name'] == name:
            return item['type']

# 通过desc查找对应结点的类型
def findNodeTypeFromDesc(desc, nodeTypeObj):
    for key in nodeTypeObj:
        item = nodeTypeObj[key]
        if item['desc'] == desc:
            return item['type']

# 连接区域结点和其他结点
def connectRegionNodeAndFactNode(tx, matcher, data, nodeTypeObj, relationshipTypeObj):
    regionNodeType = nodeTypeObj['region']['type']
    relationshipList = []
    # 1.遍历数据
    for item in data:
        factKey = REGION_NODE_RELATIONSHIP_KEY[0]
        # 2.判断是否有对应的key，有就继续下去，没有就跳过
        if factKey not in item:
            continue
        # 3.拿到对应的region结点
        regionNodeName = item['title']
        currentNode = matcher.match(regionNodeType, name=regionNodeName).first()
        for otherNodeItem in item[factKey]:
            otherNodeName = otherNodeItem['description']
            otherRelationLabel = otherNodeItem['label']
            otherNodeType = findNodeTypeFromDesc(otherRelationLabel, nodeTypeObj)
            # 4.拿到对应的结点 
            otherNode = matcher.match(otherNodeType, name=otherNodeName).first()
            # 5.拿到对应的边
            relationshipType = findRelationshipTypeFromName(otherRelationLabel, relationshipTypeObj)
            # 6.连接两个节点
            relationship = Relationship(currentNode, relationshipType, otherNode, name=otherRelationLabel)
            relationshipList.append(relationship)
    subgraphResult = Subgraph(relationships=relationshipList)
    tx.create(subgraphResult)

# 连接区域结点和英雄结点
def connectRegionNodeAndHeroNode(tx, matcher, data, nodeTypeObj, relationshipTypeObj):
    regionNodeType = nodeTypeObj['region']['type']
    heroNodeType = nodeTypeObj['hero']['type']
    relationshipType = relationshipTypeObj['belongTo']['type']
    relationshipName = relationshipTypeObj['belongTo']['name']

    relationshipList = []
    # 1.循环遍历
    for item in data:
        heroListKey = REGION_NODE_RELATIONSHIP_KEY[1]
        # 2.匹配对应的英雄所属的key
        if heroListKey not in item:
            continue
        # 3.获取区域结点
        regionNodeName = item['title']
        regionNode = matcher.match(regionNodeType, name=regionNodeName).first()
        heroList = item[heroListKey]
        for heroAlias in heroList:
            # 4.获取英雄结点
            query = f"toLower(_.alias)='{heroAlias}'"
            heroNode = matcher.match(heroNodeType).where(query).first()
            # 5.连接两个结点
            relationship = Relationship(heroNode, relationshipType, regionNode, name=relationshipName)
            relationshipList.append(relationship)
    subgraphResult = Subgraph(relationships=relationshipList)
    tx.create(subgraphResult)

# 创建区域结点
def createRegionNodeAndConnectOtherNode(graph, nodeTypeObj, data, relationshipTypeObj):
    # 1.过滤掉不需要的数据，并创建区域结点
    parseDataAndCreateRegionNode(graph, nodeTypeObj['region'], data)
    logMessage("创建区域结点成功")

    tx = graph.begin()
    matcher = NodeMatcher(graph)
    # 2.连接区域结点和其他方面的节点
    connectRegionNodeAndFactNode(tx, matcher, data, nodeTypeObj, relationshipTypeObj)
    
    # 3.连接区域结点和其他英雄的结点
    connectRegionNodeAndHeroNode(tx, matcher, data, nodeTypeObj, relationshipTypeObj)
    
    tx.commit()
    logMessage("区域结点连接其他方面结点成功")

def loadData():
    # 1.获取数据
    regionData = getRegionData()
    manageSystemData = getManageSystemData()
    magicalAttitudeData = getMagicalAttitudeData()
    technologicalLevelData = getTechnologicalLevelData()
    environmentData = getEnvironmentData()

    # 2.获取节点类型数据
    node_type_data = getNodeTypeData()
    
    # 3.获取边类型数据
    relationship_type_data = getRelationshipTypeData()

    # 4.连接数据库并返回对象
    graph = connect()

    # 5.新增统治管理节点
    addNodes(graph, node_type_data['manageSystem']['type'], manageSystemData, node_type_data['manageSystem']['desc'])
    logMessage("新增统治管理节点成功")

    # 6.新增对魔法的态度节点
    addNodes(graph, node_type_data['magicalAttitude']['type'], magicalAttitudeData, node_type_data['magicalAttitude']['desc'])
    logMessage("新增对魔法的态度节点成功")

    # 7.新增科技水平节点
    addNodes(graph, node_type_data['technologicalLevel']['type'], technologicalLevelData, node_type_data['technologicalLevel']['desc'])
    logMessage("新增科技水平节点成功")

    # 8.新增总体环境节点
    addNodes(graph, node_type_data['environment']['type'], environmentData, node_type_data['environment']['desc'])
    logMessage("新增总体环境节点成功")

    # 9.创建区域节点并连接其他相关结点
    createRegionNodeAndConnectOtherNode(graph, node_type_data, regionData, relationship_type_data)

